/**
 * 树上DDP的模板题，在单点修改的情况下求
 * Di = Ai + SIGMA{Dj, j是i的儿子}
 * 令hi是i的重儿子，则 Di = Ai + Dhi * Li
 * 其中 Li = PROD{Dj, j是i的轻儿子}
 * 写成矩阵
 * | Di | = | Li Ai | * | Dhi |
 * | 1  |   | 0  1  |   |  1  |
 * 
 * 用线段树维护矩阵。
 * 修改操作时，需要用到逆元，需要特判为0、逆元不存在的情况。
 * 因此将 Li 改成 i的非零轻儿子的乘积
 * 矩阵元素要么为Li、要么为零。
 * 再加一个零轻儿子的计数器，判断矩阵元素何时取零
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

using llt = long long;
llt const MOD = 998244353LL;

llt qpow(llt a, llt n){
    a %= MOD;
    llt ret = 1;
    while(n){
        if(n & 1) ret = ret * a % MOD;
        a = a * a % MOD;
        n >>= 1; 
    }
    return ret;
}

llt inv(llt a){return qpow(a, MOD - 2LL);}

struct HLD{ // 重链剖分

using llt = long long;

using value_type = array<llt, 2>; // [Li, Ai]
vector<value_type> data; // 线段树

using lazy_type = array<llt, 2>;
vector<lazy_type> lazy; // 延迟标记

/// 从下往上计算信息，要变动
value_type _up_(const value_type & ls, const value_type & rs) {
    // return {rs[0] * ls[0] % MOD, (rs[0] * ls[1] % MOD + rs[1]) % MOD};
    return {ls[0] *rs[0] % MOD, (ls[0] * rs[1] % MOD + ls[1]) % MOD};
}

/// 从上往下计算信息，要变动
void _dn_(int t, int s, int e, const lazy_type & delta) {
    data[t] = delta;
}

/// 辅助函数，视延迟的类型而变动
static const lazy_type & lazy_zero() {
    static const lazy_type LAZY0 = {1LL, 0LL};
    return LAZY0; 
}

/// 辅助函数，视线段树信息类型而变动
static const value_type & value_zero() {
    static const value_type VALUE0 = {1LL, 0LL};
    return VALUE0;
}

/// 几乎不用动
value_type _query(int t, int s, int e, int a, int b) {
    if(a <= s and e <= b) {
        return data[t];
    }

    int mid = (s + e) >> 1;
    value_type ans = value_zero();
    if(a <= mid) ans = _up_(ans, _query(lson(t), s, mid, a, b));
    if(mid < b) ans = _up_(ans, _query(rson(t), mid + 1, e, a, b));
    return ans;
}

/// 单点修改
void _modify(int t, int s, int e, int pos, const lazy_type & delta){
    if(s == e){
        _dn_(t, s, e, delta);
        return;
    }
    int mid = (s + e) >> 1;
    if(pos <= mid) _modify(lson(t), s, mid, pos, delta);
    else _modify(rson(t), mid + 1, e, pos, delta);
    _pushUp(t);
    return;
}

/// 这个函数不用动
void _pushUp(int t) {
    data[t] = _up_(data[lson(t)], data[rson(t)]);
}

/// 这两个函数不用变动
static int lson(int x) {return x << 1;}
static int rson(int x) {return lson(x) | 1;}

int N;
/// 树结构, 1-index
vector<vector<int>> g;
/// 点权值
vector<llt> weight;

/// 建单向边
void mkDiEdge(int a, int b){
    g[a].push_back(b);
}
/// 建双向边
void mkBiEdge(int a, int b){
    mkDiEdge(a, b); mkDiEdge(b, a);
}

/// 树链剖分结构
struct node_t{
    int parent; // 父节点
    int hson;   // 重儿子
    int depth;  // 该节点的深度, 根节点深度为0
    int size;   // 本节点所领子树的节点总数
    int top;    // 本节点所在重链的顶，采用的是原树编号
    int bot;    // 本节点所在重链的底，但是采用的是新编号
    int nid;    // 本节点在线段树中的编号, 即dfs序
    int mdes;   // 本节点所领子树的线段树编号均在[nid, mdes]中，采用的是新编号
};

int root; // 树根
vector<int> nid2old; // nid2old[i]表示线段树中第i个节点在原树中的编号
int timestamp; // 辅助变量
vector<node_t> nodes;

vector<llt> D;
vector<llt> L;
vector<int> Z; // Zi只是i的轻儿子中D为零的数量

/// 递归找重边
void _dfsHeavyEdge(int u, int p, int d){
    auto & n = nodes[u];
    n.parent = p;
    n.depth = d;
    n.size = 1;
    D[u] = weight[u];
    llt tmp = 1;

    for(auto v : g[u]){
        if(v == p) continue;
        _dfsHeavyEdge(v, u, d + 1);
        n.size += nodes[v].size;
        if(nodes[n.hson].size < nodes[v].size) n.hson = v;
        tmp = tmp * D[v] % MOD;       
    }
    if(n.hson) D[u] = (D[u] + tmp) % MOD;
    return;
}

/// 递归找重链
void _dfsHeavyPath(int u, int top){
    auto & n = nodes[u];
    n.top = top;
    nid2old[n.mdes = n.nid = ++timestamp] = u;
    L[u] = 1;

    if(0 == n.hson) return (void)(n.bot = n.nid);

    _dfsHeavyPath(n.hson, top);
    n.mdes = max(n.mdes, nodes[n.hson].mdes);
    n.bot = nodes[n.hson].bot;

    for(auto v : g[u]){
        if(v != n.parent and v != n.hson){
            _dfsHeavyPath(v, v);
            n.mdes = max(n.mdes, nodes[v].mdes);
            if(D[v]){
                L[u] = (L[u] * D[v]) % MOD;
            }else{
                Z[u] += 1;
            }            
        }
    }

    return;
}
/// 递归建线段树
void _build(int t, int s, int e) {
    if(s == e) {
        data[t] = {L[nid2old[s]], weight[nid2old[s]]}; // 注意线段树编号与原树编号存在转换
        return; 
    }
    int mid = (s + e) >> 1;
    _build(lson(t), s, mid);
    _build(rson(t), mid + 1, e);
    _pushUp(t);
}

/// 初始化, n是树的点数
void init(int n){
    N = n;
    timestamp = 0;
    /// 初始化树结构
    g.assign(N + 1, {});
    weight.assign(N + 1, 0);
    /// 初始化树链结构
    nodes.assign(N + 1, {0, 0, 0, 0, 0, 0, 0});
    nid2old.assign(N + 1, 0);
    /// 初始化线段树结构
    data.assign(N + 1 << 2, value_zero());
    lazy.assign(N + 1 << 2, lazy_zero());    
    /// 初始化DP数据
    D.assign(N + 1, {});
    L.assign(N + 1, {});
    Z.assign(N + 1, 0);
    return;
}

/// 在输入所有数据以后构建
void build(int root){
    /// 建树链
    _dfsHeavyEdge(this->root = root, 0, 0);
    _dfsHeavyPath(root, root);
    /// 建线段树
    _build(1, 1, N);
}

/// 求原树上x和y的LCA
int lca(int x, int y){
    while(nodes[x].top != nodes[y].top){
        if(nodes[nodes[x].top].depth < nodes[nodes[y].top].depth) y = nodes[nodes[y].top].parent;
        else x = nodes[nodes[x].top].parent;
    }
    return nodes[x].depth <= nodes[y].depth ? x : y;
}

/// 查询原树上x的信息，就是线段树上[nid, bot]的区间信息
value_type query(int x){
    return _query(1, 1, N, nodes[x].nid, nodes[x].bot);
}

/// 原树上的单点修改
void modify(int x, llt delta){
    if(weight[x] == delta) return;
    
    weight[x] = delta;
    /// 修改
    _modify(1, 1, N, nodes[x].nid, {L[x], delta});

    while(1){
        auto top = nodes[x].top;
        auto parent = nodes[top].parent;
        if(0 == parent) break;

        /// 查询当前top的值并与D进行对比
        auto curTop = query(top);
        if(D[top] == curTop[1]) break;

        // auto tt = _query(1, 1, N, nodes[parent].nid, nodes[parent].nid);

        if(D[top]){
            if(curTop[1]){
                auto oL = L[parent];
                llt curL = oL * inv(D[top]) % MOD * curTop[1] % MOD;        
                D[top] = curTop[1];
                L[parent] = curL;    
                if(0 == Z[parent]){ // 没有0儿子才需要修改
                    // if(not (tt[0] == oL)) while(1);
                    /// 修改parent
                    _modify(1, 1, N, nodes[parent].nid, {curL, weight[parent]});                     
                }else{
                    // assert(tt[0] == 0);
                    break;
                }                           
            }else{
                auto oL = L[parent];
                llt curL = oL * inv(D[top]) % MOD;        
                D[top] = curTop[1];
                L[parent] = curL; 
                if(1 == (Z[parent] += 1)){
                    // assert(tt[0]);
                    /// 修改parent
                    _modify(1, 1, N, nodes[parent].nid, {0, weight[parent]});                      
                }else{
                    // assert(tt[0] == 0);
                    break;
                }
            }
        }else{
            // assert(tt[0] == 0);
            // assert(curTop[1]);
            if(--Z[parent]){
                auto oL = L[parent];
                llt curL = oL * curTop[1] % MOD;
                L[parent] = curL;     
                D[top] = curTop[1];     
                break;           
            }else{
                auto oL = L[parent];
                llt curL = oL * curTop[1] % MOD;
                L[parent] = curL;     
                D[top] = curTop[1];
                /// 修改parent
                _modify(1, 1, N, nodes[parent].nid, {curL, weight[parent]}); 
            }
        }
        x = parent;
    }
    return;
}

};

HLD Tree;
int N, Q, Root;

void work(){
    cin >> N >> Q;
    Tree.init(N);
    for(int p,i=2;i<=N;++i){
        cin >> p;
        Tree.mkDiEdge(p, i);
    }
    for(int i=1;i<=N;++i) cin >> Tree.weight[i];
    Tree.build(Root = 1);

    for(int v,x,q=1;q<=Q;++q){
        cin >> v >> x;
        Tree.modify(v, x);
        auto ans = Tree.query(1);
        cout << ans[1] << "\n";
    }
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int nofkase = 1;
    // cin >> nofkase;
    while(nofkase--) work();
    return 0;
}